# == Schema Information
# Schema version: 37
#
# Table name: users
#
#  id                        :integer(11)   not null, primary key
#  login                     :string(255)   
#  email                     :string(255)   
#  crypted_password          :string(40)    
#  salt                      :string(40)    
#  created_at                :datetime      
#  updated_at                :datetime      
#  remember_token            :string(255)   
#  remember_token_expires_at :datetime      
#  home_phone                :string(255)   
#  cell_phone                :string(255)   
#  work_phone                :string(255)   
#  other_phone               :string(255)   
#  address1                  :string(255)   
#  address2                  :string(255)   
#  address3                  :string(255)   
#  city                      :string(255)   
#  state                     :string(255)   
#  zip                       :integer(11)   
#  activation_code           :string(40)    
#  activated_at              :datetime      
#  password_reset_code       :string(40)    
#  first_name                :string(255)   
#  last_name                 :string(255)   
#  site_id                   :integer(11)   
#  position                  :string(255)   
#  last_login                :datetime      
#

require 'digest/sha1'
class User < ActiveRecord::Base
  # Virtual attribute for the unencrypted password
  attr_accessor :password   

  validates_presence_of     :email, :first_name, :last_name, :site_id
  validates_presence_of     :password,                   :if => :password_required?
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, :within => 4..40, :if => :password_required?
  validates_confirmation_of :password,                   :if => :password_required?
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :email, :case_sensitive => false  
  validates_format_of :email, :with => /(^([^@\s]+)@((?:[-_a-z0-9]+\.)+[a-z]{2,})$)|(^$)/i
  before_save :encrypt_password    
  before_create :make_activation_code


  has_many :submissions
  has_and_belongs_to_many :roles 
  belongs_to :site
      
  def self.find_admins
    User.find(:all, 
      :joins => "JOIN roles_users on (roles_users.user_id = users.id)
                 JOIN roles on (roles_users.role_id = roles.id)",
      :conditions => "roles.name in ('Admin', 'AdminAssist')")
  end
  
  def self.find_managers
    User.find(:all, 
      :joins => "JOIN roles_users on (roles_users.user_id = users.id)
                 JOIN roles on (roles_users.role_id = roles.id)",
      :conditions => "roles.name in ('Admin', 'AdminAssist')",
      :include => ['sites', 'roles'])
  end       
  
  
  def display_name
    "#{self.first_name} #{self.last_name}"
  end  
    
  # TODO: is_admin, is_judge, is_manager, is_seeker need a lot of work.  These are just
  #       hacks to get this working.  This should be implemented using the "method_missing"
  #       method.  Also, these should not make a query every time!  We need to fix this someday.
  def is_admin?
    @is_admin ||= (not (self.roles.find_by_name("Admin") == nil))
  end   
  
  def is_judge?
    @is_judge ||= (not (self.roles.find_by_name("Judge") == nil))
  end 

  def is_manager?
    @is_manager ||= (not (self.roles.find_by_name("Manager") == nil))
  end 

  def is_seeker?
    @is_seeker ||= (not (self.roles.find_by_name("Seeker") == nil))
  end   
  
  def is_adminasst?
    @is_adminasst ||= (not (self.roles.find_by_name("AdminAssist") == nil))
  end

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(email, password)
    u = find :first, :conditions => ['email = ? and activated_at IS NOT NULL', email]    
    u && u.authenticated?(password) ? u : nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    self.remember_token_expires_at = 2.weeks.from_now.utc
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end 
  
  # Activates the user in the database.
  def activate
    @activated = true
    update_attributes(:activated_at => Time.now.utc, :activation_code => nil)
  end

  # Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end 
  
  def forgot_password
    @forgotten_password = true
    self.make_password_reset_code
  end

  def reset_password
    # First update the password_reset_code before setting the 
    # reset_password flag to avoid duplicate email notifications.
    update_attributes(:password_reset_code => nil)
    @reset_password = true
  end

  def recently_reset_password?
    @reset_password
  end

  def recently_forgot_password?
    @forgotten_password
  end 
  
  def invite
    @invited = true
    self.make_password_reset_code
  end
  
  def recently_invited?
    @invited
  end 

  protected
    # before filter 
    def encrypt_password
      return if password.blank?
      self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
      self.crypted_password = encrypt(password)
    end
    
    def password_required?
      crypted_password.blank? || !password.blank?
    end    
    
    # If you're going to use activation, uncomment this too
    def make_activation_code
      self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end      
    
    def make_password_reset_code
      self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end
     
end
